package come.example.domain.strategy.service;

import come.example.domain.strategy.model.entity.RaffleAwardEntity;
import come.example.domain.strategy.model.entity.RaffleFactorEntity;
import come.example.domain.strategy.model.entity.RuleActionEntity;
import come.example.domain.strategy.model.entity.StrategyAwardEntity;
import come.example.domain.strategy.model.vo.RuleLogicCheckTypeVO;
import come.example.domain.strategy.model.vo.StrategyAwardRuleModelVO;
import come.example.domain.strategy.repository.IStrategyRepository;
import come.example.domain.strategy.service.armory.IStrategyDispatch;
import come.example.domain.strategy.service.rule.chain.ILogicChain;
import come.example.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import come.example.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import come.example.types.enums.ResponseCode;
import come.example.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {
        // 策略仓储服务 -> domain层像一个大厨，仓储层提供米面粮油
        protected IStrategyRepository repository;
        // 策略调度服务 -> 只负责抽奖处理，通过新增接口的方式，隔离职责，不需要使用方关心或者调用抽奖的初始化
        protected IStrategyDispatch strategyDispatch;

        // 为啥这里不能private？- 不然子类没法去使用
        protected final DefaultChainFactory defaultChainFactory;

        protected final DefaultTreeFactory defaultTreeFactory;

    public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory, DefaultTreeFactory defaultTreeFactory) {
            this.repository = repository;
            this.strategyDispatch = strategyDispatch;
            this.defaultChainFactory = defaultChainFactory;
            this.defaultTreeFactory = defaultTreeFactory;
    }

        @Override
        public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
            // 1. 参数校验
            String userId = raffleFactorEntity.getUserId();
            Long strategyId = raffleFactorEntity.getStrategyId();
            if (null == strategyId || StringUtils.isBlank(userId)) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }

            // 调用两个抽象方法
            // 2. 责任链抽奖计算【这步拿到的是初步的抽奖ID，之后需要根据ID处理抽奖】注意：黑名单、权重等非默认抽奖的直接返回抽奖结果
            DefaultChainFactory.StrategyAwardVO chainStrategyAwardVO = raffleLogicChain(userId, strategyId);
            log.info("抽奖策略计算-责任链 {} {} {} {}", userId, strategyId, chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getLogicModel());
            if(!DefaultChainFactory.LogicModel.RULE_DEFAULT.getCode().equals(chainStrategyAwardVO.getLogicModel())){
                return buildRaffleAwardEntity(strategyId, chainStrategyAwardVO.getAwardId(), null);
            }

            // 3. 规则树抽奖过滤【奖品ID，会根据抽奖次数判断、库存判断、兜底返回最终的可获奖品信息】
            DefaultTreeFactory.StrategyAwardVO treeStrategyAwardVO = raffleLogicTree(userId, strategyId, chainStrategyAwardVO.getAwardId());
            log.info("抽奖策略计算-规则树 {} {} {} {}", userId, strategyId, treeStrategyAwardVO.getAwardId(), treeStrategyAwardVO.getAwardRuleValue());

            // 4.返回抽奖结果
            return buildRaffleAwardEntity(strategyId, treeStrategyAwardVO.getAwardId(), treeStrategyAwardVO.getAwardRuleValue());
        }

        // 构造一个build函数，这样就不用改动很多
        private RaffleAwardEntity buildRaffleAwardEntity(Long strategyId, Integer awardId, String awardConfig) {
            StrategyAwardEntity strategyAward = repository.queryStrategyAwardEntity(strategyId, awardId);
            return RaffleAwardEntity.builder()
                    .awardId(awardId)
                    .awardConfig(awardConfig)
                    .sort(strategyAward.getSort()) // 在这里拿到sort
                    .build();
        }

    /**
     * 抽奖计算，责任链抽象方法
     */
    public abstract  DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId);

    /**
     * 抽奖结果过滤，决策树抽象方法
     */

    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);



    //protected abstract RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics);

    //protected abstract RuleActionEntity<RuleActionEntity.RaffleCenterEntity> doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics);

}
